#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>


// 子进程创建fork

//int main()
//{
//    pid_t pid = fork();
//
//    if (pid == 0)
//    {
//        // 子进程
//        printf("I am son. My pid is %d and my ppid is %d\n", getpid(), getpid());
//    }
//    else if (pid > 0)
//    {
//        printf("I am father. My pid is %d\n", getpid());
//    }
//    else 
//    {
//        printf("子进程创建失败\n");
//    }
//    return 0;
//}

// 进程终止
// 错误码
//int main()
//{
//    int i = 0;
//    for (; i <= 200; i++)
//    {
//        printf("%d -> %s\n", i, strerror(i));
//    }
//    return 0;
//}


// _exit与exit
//void test()
//{
//    printf("hello exit\n");
//   // exit(100);
//   _exit(100);
//}
//
//int main()
//{
//    test();
//    return 0;
//}

// 进程等待

// 有僵尸进程的情况
//int main()
//{
//    pid_t pid = fork();
//
//    if (pid < 0)
//    {
//        perror("fork");
//        return 1;
//    }
//    else if (pid == 0)
//    {
//        int cnt = 5;
//        while (cnt--)
//        {
//            printf("I am child. pid: %d. ppid:%d. cnt: %d\n", getpid(), getppid(), cnt);
//            sleep(1);
//        }
//       // 子进程打印五次退出，父进程还在继续执行，此时子进程就成了僵尸进程
//        exit(0);
//    }
//    else 
//    {
//        while (1)
//        {
//            printf("I am parent. pid: %d. ppid: %d\n", getpid(), getppid());
//            sleep(1);
//        }
//    }
//    return 0;
//}

// wait - 回收僵尸进程
//int main()
//{
//    pid_t pid = fork();
//
//    if (pid < 0)
//    {
//        perror("fork");
//        return 1;
//    }
//    else if (pid == 0)
//    {
//        int cnt = 5;
//        while (cnt--)
//        {
//            printf("I am child. pid: %d. ppid:%d. cnt: %d\n", getpid(), getppid(), cnt);
//            sleep(1);
//        }
//        // 子进程打印五次退出，父进程还在继续执行，此时子进程就成了僵尸进程
//        exit(0);
//    }
//    else 
//    {
//        int cnt = 10;
//        while (cnt--)
//        {
//            printf("I am parent. pid: %d. ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);
//            sleep(1);
//        }
//        pid_t res = wait(NULL);
//        if (res == pid) // 如果wait的返回值等于子进程pid，说明回收成功
//        {
//            printf("回收成功，PID：%d\n", res);
//        }
//        sleep(5);
//    }
//    return 0;
//}

// 多进程等待

//int main()
//{
//    int i = 0;
//    for (; i < 3; i++)
//    {
//        // 创建三个进程
//        pid_t pid = fork();
//
//        if (pid == 0)
//        {
//            // 子进程
//            int cnt = 3;
//            while (cnt--)
//            {
//                printf("I am child. My pid is %d. My ppid is %d. My cnt is %d\n", getpid(), getppid(), cnt);
//                sleep(1);
//            }
//            exit(0);
//        }
//         // 父进程
//         printf("create child process success: %d\n", pid);
//    }
//    // 停顿10秒，方便查看僵尸状态
//    sleep(10);
//
//    // 等待进程：杀死僵尸进程
//    i = 0;
//    for (; i < 3; i++)
//    {
//        pid_t res = wait(NULL);
//        if (res > 0)
//        {
//            printf("回收成功：%d\n", res);
//        }
//    }
//    sleep(3);
//    return 0;
//}

// 阻塞等待
//int main()
//{
//    pid_t pid = fork();
//
//    if (pid == 0)
//    {
//        // 子进程
//        while (1) // 子进程一直打印不退出
//        {
//            printf("I am child. My pid is %d. My ppid is %d\n", getpid(), getppid());
//            sleep(1);
//        }
//    }
//    else 
//    {
//        // 父进程
//        wait(NULL);
//    }
//    return 0;
//}


// waitpid() - 父进程获取子进程状态的演示

//int main()
//{
//    pid_t pid = fork();
//
//    if (pid == 0)
//    {
//        // 子进程
//        int cnt = 3;
//        while (cnt--)
//        {
//            printf("I am child. My pid is %d. My ppid is %d. My cnt is %d\n", getpid(), getppid(), cnt);
//            sleep(1);
//        }
//        // 非法访问：验证退出信号~
//        //int* ptr = NULL;
//        //*ptr = 666;
//        exit(3);
//    }
//    else if (pid > 0) 
//    {
//        // 父进程
//        int cnt = 5;
//        while (cnt--)
//        {
//            printf("I am father. My pid is %d. My ppid is %d. My cnt is %d\n", getpid(), getppid(), cnt);
//            sleep(1);
//        }
//        int status = 0;
//        // status做输出型参数，传入地址，通过系统调用接口waitpid让操作系统帮我们获取子进程的状态
//        pid_t res = waitpid(pid,&status, 0);
//        if (res == pid)
//        {
//           // printf("回收成功：退出信号：%d, 退出码：%d\n", status & 0x7F, (status >> 8) & 0xFF);
//           // printf("回收成功：退出信号：%d, 退出码：%s\n", status & 0x7F, strerror((status >> 8) & 0xFF)); 
//           printf("回收成功：退出信号：%d, 退出码：%s\n", WTERMSIG(status), strerror(WEXITSTATUS(status))); 
//        }
//    
//        sleep(3);
//    }
//    return 0;
//}


// 非阻塞轮询WNOHANG


int main()
{
    pid_t pid = fork();

    if (pid == 0)
    {
        // 子进程
        int cnt = 5;
        while (cnt--)
        {
            printf("I am child,我还需要%d秒. My pid is %d. My ppid is %d\n", cnt, getpid(), getppid());
            sleep(1);
        }
        exit(0);
    }
    else if (pid > 0)
    {
        // 父进程
        while (1)
        {
            int status = 0;
            pid_t res = waitpid(pid, &status, WNOHANG);
            if (res > 0) // 这条判断本质是res == 子进程PID为真，表示回收子进程成功
            {
                printf("回收成功：退出信号：%d, 退出码：%s\n", WTERMSIG(status), strerror(WEXITSTATUS(status))); 
                // 回收成功后退出循环
                break;
            }
            else if (res < 0) // 回收子进程失败
            {
                perror("waitpid");
                // 可能没有子进程要回收了等情况
                break;
            }
            else // res == 0 父进程还需要等待子进程退出
            {
                printf("Hi. 子进程%d. 你好了吗？？？\n", pid);
                sleep(1);
            }
        }
    }
    else 
    {
        // 子进程创建失败哦
        perror("fork");
        exit(1);
    }
    return 0;
}
